<?php
/**
 *  全局时间类方法
 * 
 * Copyright (c) 2014~2019 https://desion.net All rights reserved.
 * Author: 阿林 QQ:120867629 <linhong00@gmail.com>
 */
declare (strict_types = 1);
namespace dsphp\helper;

class TimeHelper
{
    // 返回状态
    private $_returnType = '';
    // 类型 date 日期 datetime 日期时间 timestamp 时间戳， int 整数
    private $_checkStatus = true;


    /**
     * 设置返回时间戳还是时间
     *
     * @param boolean $status 状态 true 时间戳 false 日期
     * @return this
     */
    public function returnType(string $type = '')
    {
        if ($type == 'date') {
            $type = 'Y-m-d';
        } elseif ($type == 'datetime') {
            $type = 'Y-m-d H:i:s';
        } else {
            $type = '';
        }

        $this->_returnType = $type;

        return $this;
    }

    /**
     * 检测类型，空为不检测
     *
     * @param boolean $status  类型
     * @return this
     */
    public function isCheck(bool $status = true) 
    {
        $this->_checkStatus = $status;
        return $this;
    }

    /**
     * 检测日期格式
     *
     * @param mixed $data  日期或整数
     * @param string $type  类型
     * @return void
     */
    public function check($data, $type = null):bool
    {
        if ($this->_checkStatus === false) {
            return true;
        }

        switch ($type)
        {
            case 'int':
                $reg = '/^[1-9]\d*$/';
                break;
            case 'date':
            default :
                // 和date一致
                // $reg = '/^\d{4}-\d{2}-\d{2}$/';
                $reg = '/^201\d-(0[1-9]|1[0|1|2])-([0|1|2]\d|31|30)$/';
        }

        return (preg_match($reg, $data)) ? true : false;
    }

    /**
     * 返回今日开始和结束的时间戳
     */
    public function today():array
    {
        return $this->isCheck(false)->dateToTime(date('Y-m-d'));
    }

    /**
     * 返回昨日开始和结束的时间戳
     */
    public function yesterday():array
    {
        return $this->isCheck(false)->dateToTime(date('Y-m-d', strtotime('-1 day')));
    }

    /**
     * 返回指定日期开始和结束的时间戳
     * 
     * @param date $date  日期
     */
    public function dateToTime(string $date)
    {
        $result = $this->check($date, 'date');
        if ($result === false) {
            return false;
        }

        list($year, $month, $day) = $this->_explode($date);
        return $this->_getTimes($day, $month, $year);
    }

    /**
     * 返回本周开始和结束的时间戳
     * 周一开始周日结束
     * 
     * @param boolean $timestamp  true 时间戳 false 日期 
     */
    public function week():array
    {
        return $this->isCheck(false)->dateToWeek('');
    }

    /**
     * 返回上周开始和结束的时间戳
     *
     * @param boolean $timestamp  true 时间戳 false 日期 
     */
    public function lastWeek():array
    {
        $timestamp = time();
        $timestamp = [
            strtotime(date('Y-m-d', strtotime("last week Monday", $timestamp))),
            strtotime(date('Y-m-d', strtotime("last week Sunday", $timestamp))) + 86400 - 1
        ];

        return $this->_returnType == '' ? $timestamp : $this->_formatTime($timestamp, $this->_returnType);
    }

    /**
     * 根据指定日期获取所在周的开始和结束
     *
     * @param string $date
     */
    public function dateToWeek(string $date)
    {
        $result = $this->check($date, 'date');
        if ($result === false) {
            return false;
        }

        if ($date) {
            $date = date('Y-m-d-w', strtotime($date));
        } else {
            $date = date('Y-m-d-w');
        }
        // w 是周日0 周一-六 是1-6
        list($year, $month, $day, $week) = $this->_explode($date);
        if ($week) {
            $ds = $day - $week + 1;
            $de = $ds + 6 ; // $d - $w + 7
        } else {
            $ds = $day - 6;
            $de = $day;
        }

        return $this->_getTimes([$ds, $de], $month, $year);
    }

    /**
     * 返回本月开始和结束的时间戳
     * 
     */
    public function month():array
    {
        list($year, $month, $day) = $this->_explode(date('Y-m-t'));
        return $this->isCheck(false)->_getTimes([1, $day], $month, $year);
    }

    /**
     * 返回上个月开始和结束的时间戳
     * 
     * @param boolean $timestamp  true 时间戳 false 日期 
     */
    public function lastMonth():array
    {
        return $this->dateToMonth(1);
    }

    /**
     * 返回指定日期开始和结束的时间戳
     * 
     * @param mixed $data  日期或正整数
     */
    public function dateToMonth($data):array
    {
        if (is_numeric($data)) {
            $year  = (int)date('Y');
            $month = date('m') - intval($data);
        } else {
            $result = $this->check($data, 'date');
            if ($result === false) {
                return false;
            }

            list($year, $month, $day) = $this->_explode($data);
        }

        $begin = mktime(0, 0, 0, $month, 1, $year);
        $end   = mktime(23, 59, 59, $month, (int)date('t', $begin), $year);

        $data = [$begin, $end];
        return $this->_returnType == '' ? $data : $this->_formatTime($data, $this->_returnType);
    }

    /**
     * 返回今年开始和结束的时间戳
     *
     * @return array
     */
    public function year()
    {
        return $this->numsToYear(0);
    }

    /**
     * 返回去年开始和结束的时间戳
     *
     */
    public function lastYear():array
    {
        return $this->numsToYear(1);
    }

    /**
     * 返回今年开始和结束的时间戳
     *
     * @param integer $year   
     */
    public function numsToYear(int $year, $isYear = false):array
    {
        if ($isYear === false) {
            $year = date('Y') - $year;
        }

        $year = [
            mktime(0, 0, 0, 1, 1, $year),
            mktime(23, 59, 59, 12, 31, $year)
        ];

        return $this->_returnType == '' ? $year : $this->_formatTime($year, $this->_returnType);
    }

    /**
     * 获取几天前零点到现在/昨日结束的时间戳
     *
     * @param  int  $day 天数
     * @param  bool $now 返回现在或者昨天结束时间戳
     * @return array
     */
    public function dayToNow(int $nums = 1, $now = true)
    {
        if ($now === true) {
            $now = date('Y-m-d');
        } elseif (is_string($now)) {
            $result = $this->check($now, 'date');
            if ($result === false) {
                return false;
            }
        } else {
            $now = date('Y-m-d', strtotime('-1 day'));
        }

        list($year, $month, $day) = $this->_explode($now);

        $day = [
            $day - $nums,
            $day
        ];

        return $this->_getTimes($day, $month, $year);
    }

    /**
     * 生成时间戳(如果日期并转成日期)
     *
     * @param mixed  $day    日
     * @param integer $month  月份
     * @param integer $year   年份
     */
    private function _getTimes($day, int $month, int $year):array
    {
        if (! is_array($day)) {
            $day = [$day, $day];
        }
        $time = [
            mktime(0, 0, 0, $month, $day[0], $year),
            mktime(23, 59, 59, $month, $day[1], $year)
        ];

        $format = $this->_returnType;

        if ($format == '') {
            return $time;
        }

        return $this->_formatTime($time, $format);
    }

    /**
     * 格式化时间戳
     *
     * @param array $time
     */
    private function _formatTime(array $time, string $format):array
    {
        $time[0] = date($format, $time[0]);
        $time[1] = date($format, $time[1]);

        return $time;
    }

    /**
     * 切割并转整数
     *
     * @param string $date 
     */
    private function _explode(string $date):array
    {
        
        $date = explode('-', $date);
        foreach ($date as $k => $v) {
            $date[$k] = intval($v);
        }

        return $date;
    }
}